package com.valeandre.euroro.net;


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.codehaus.jackson.map.ObjectMapper;
import org.simpleframework.xml.core.Persister;

import com.valeandre.euroro.model.Prices;
import com.valeandre.euroro.model.XmlGold;
import com.valeandre.euroro.utils.ResBundle;


	
	public class NetworkService {

		private static final int BUFFER_SIZE = 16384;
		private static final int CONNECTION_TIMEOUT = 12000;
		private static final int SOCKET_TIMEOUT = 16000;

		private static NetworkService mInstance;
		private ExecutorService mExecutor;

		public static NetworkService getInstance() {
			if (mInstance == null) {
				mInstance = new NetworkService();
			}
			return mInstance;
		}

		private NetworkService() {
			mExecutor = Executors.newFixedThreadPool(3, new ThreadFactory() {

				public Thread newThread(Runnable r) {
					Thread t = new Thread(r);
					t.setPriority(Thread.NORM_PRIORITY);
					return t;
				}
			});
		}

		private abstract class NetworkTask implements Runnable {

			protected NetworkServiceListener mListener;
			protected ObjectMapper mObjectMapper;
			protected DefaultHttpClient mClient;
			protected String mEndpoint;
			protected Persister mSerializer;

			public NetworkTask(NetworkServiceListener listener) {
				mListener = listener;
				mObjectMapper = new ObjectMapper();
				mSerializer = new Persister();
				mClient = new DefaultHttpClient();
//				HttpConnectionParams.setConnectionTimeout(mClient.getParams(), 15000);
				setConnectionTimeout(mClient);
			}

			public void run() {
				runTask();
			}

			protected byte[] loadAll(InputStream input) throws IOException {
				ByteArrayOutputStream baos = new ByteArrayOutputStream();

				byte[] buffer = new byte[BUFFER_SIZE];
				int read;
				while ((read = input.read(buffer)) != -1) {
					baos.write(buffer, 0, read);
				}

				return baos.toByteArray();
			}

			public abstract void runTask();
		}
		
		private void setConnectionTimeout(DefaultHttpClient httpClient) {
			setConnectionTimeout(httpClient, CONNECTION_TIMEOUT, SOCKET_TIMEOUT);
		}
		
		private void setConnectionTimeout(DefaultHttpClient httpClient, int connTimeout, int socketTimeout) {

			connTimeout = connTimeout == -1 ? CONNECTION_TIMEOUT : connTimeout;
			socketTimeout = socketTimeout == -1 ? SOCKET_TIMEOUT : socketTimeout;
			HttpParams httpParameters = new BasicHttpParams();
			HttpConnectionParams.setConnectionTimeout(httpParameters, connTimeout);
			HttpConnectionParams.setSoTimeout(httpParameters, socketTimeout);
			httpClient.setParams(httpParameters); 

		}
		
		
		private class GetConversionValuesTask extends NetworkTask {

			public GetConversionValuesTask(NetworkServiceListener listener) {
				super(listener);
				mEndpoint = ResBundle.URL_CONVERSION;
			}

			@Override
			public void runTask() {
				HttpResponse response = null;

				try {
					HttpGet request = new HttpGet(mEndpoint);

					response = mClient.execute(request);

					StatusLine status = response.getStatusLine();

					if (status.getStatusCode() == HttpStatus.SC_OK || status.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
//						XmlGold xml = mSerializer.read(XmlGold.class, response.getEntity().getContent(), false);
						Prices xml = mSerializer.read(Prices.class, response.getEntity().getContent(), false);
						mListener.conversionPerformed(xml);
					} else {
						mListener.conversionFailed(status.getStatusCode());
					}

				} catch (Exception e) {
					e.printStackTrace();
					mListener.conversionFailed(e);
				}

			}

		}
		
		
		
		public void getConversionValues(NetworkServiceListener listener) {
			GetConversionValuesTask task = new GetConversionValuesTask(listener);
			mExecutor.execute(task);
		}


}
